#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#include "../src/estep.c"

typedef struct _EstepTestDatum EstepTestDatum ;
struct _EstepTestDatum 
{ 
  struct
    {
      float     priorz[5];
      Rating    ratings[6];
      float     logalpha;
      float     loglambda[4];
      float     tau[4*(5-1)];
      int       clamp;
    }                   inputs;

  float pz[5];
};

static void
test_estep (void)
{
  EstepTestDatum data[] = 
    {{{{0.79147, 0.216789, 0.415948, 0.0294446,  0.454082}, {{2, 1}, {1, 0}, {3, 0}, {3, 2}, {2, 4}, {1, 3}},  0.558853, {0.0805605, 0.192537, 0.959584, 0.3046}, {0.155938,  0.176819, 0.0671695, 0.183372, 0.133103, 0.155876, 0.0532786,  0.0466481, 0.0617126, 0.135431, 0.122176, 0.0247331, 0.140402,  0.0842057, 0.163882, 0.181375}, -1}, {2.12564e-15, 0.000107927,  0.999826, 0.0000664732,  1.43957e-16}}, {{{0.391584, 0.36533, 0.348024, 0.205504,  0.199047}, {{2, 4}, {2, 4}, {1, 4}, {3, 4}, {3, 0}, {2, 0}},  0.405746, {0.0434241, 0.425812, 0.314953, 0.069899}, {0.0253124,  0.15206, 0.107115, 0.160701, 0.178664, 0.0903471, 0.171684,  0.0385247, 0.153931, 0.149945, 0.0874783, 0.0746424, 0.172556,  0.092732, 0.00916158, 0.00157638}, 1}, {1.16934e-20,  0.000938714, 0.0186328, 0.979397,  0.00103109}}, {{{0.258156, 0.846761, 0.602135, 0.471331,  0.832344}, {{0, 3}, {2, 3}, {3, 4}, {2, 4}, {1, 3}, {0, 1}},  0.531809, {0.532236, 0.34477, 0.0720454, 0.996234}, {0.145746,  0.0902896, 0.124062, 0.0275629, 0.107221, 0.136358, 0.174117,  0.140085, 0.0325789, 0.163802, 0.0813851, 0.130923, 0.0310026,  0.0608513, 0.0297539, 0.161571}, 4}, {1.51421e-38,  2.16145e-20, 1.03919e-8, 0.000370372,  0.99963}}, {{{0.832925, 0.316425, 0.276045, 0.0206411,  0.488156}, {{0, 0}, {3, 4}, {1, 4}, {1, 2}, {0, 2}, {3, 1}},  0.24438, {0.279811, 0.291911, 0.0367075, 0.62407}, {0.0283993,  0.151161, 0.0709832, 0.150697, 0.0883147, 0.118582, 0.107181,  0.0693118, 0.157392, 0.0875793, 0.0463294, 0.0395579, 0.195821,  0.177004, 0.0797444, 0.176273}, 0}, {9.2576e-8, 0.0000591237,  0.884011, 0.115929,  4.70643e-7}}, {{{0.864378, 0.910566, 0.636984, 0.42325,  0.572467}, {{1, 2}, {3, 2}, {3, 2}, {0, 1}, {1, 4}, {3, 4}},  0.873859, {0.0129143, 0.281254, 0.816663, 0.518943}, {0.0518859,  0.167936, 0.0447508, 0.196608, 0.182574, 0.0105442, 0.157171,  0.150278, 0.143016, 0.0147231, 0.180168, 0.0705341, 0.166743,  0.074111, 0.00729213, 0.0884208}, -1}, {8.60198e-32,  3.01742e-12, 0.065551, 0.934449,  7.43866e-8}}, {{{0.947305, 0.463993, 0.568245, 0.183818,  0.666051}, {{3, 0}, {0, 4}, {1, 1}, {3, 0}, {3, 2}, {1, 1}},  0.64733, {0.0493018, 0.924388, 0.826371, 0.423576}, {0.0132525,  0.00230348, 0.15473, 0.127544, 0.062974, 0.0592873, 0.140007,  0.147376, 0.19244, 0.092544, 0.065896, 0.140084, 0.104019,  0.0531975, 0.0764351, 0.0472853}, 3}, {1.22329e-6, 0.99714,  0.00285842, 1.06677e-8,  7.28187e-34}}, {{{0.0821698, 0.716124, 0.589096, 0.902549,  0.157782}, {{3, 3}, {1, 3}, {3, 4}, {2, 0}, {3, 0}, {2, 2}},  0.889753, {0.16552, 0.836287, 0.146264, 0.116103}, {0.10556,  0.104283, 0.169966, 0.0832136, 0.158184, 0.111843, 0.0774216,  0.0173176, 0.0181001, 0.00782435, 0.0242241, 0.140883, 0.170815,  0.0174542, 0.00779012, 0.197658}, -1}, {4.90485e-21,  1.48428e-6, 0.996839, 0.00315959,  6.49965e-14}}, {{{0.184722, 0.881169, 0.0985351, 0.0994587,  0.348436}, {{3, 4}, {2, 3}, {2, 3}, {3, 2}, {0, 0}, {1, 2}},  0.734905, {0.982432, 0.571658, 0.827019, 0.885077}, {0.113273,  0.156147, 0.0535604, 0.0995938, 0.0959551, 0.138047, 0.045736,  0.0753697, 0.155073, 0.167232, 0.0282818, 0.0675796, 0.157415,  0.114237, 0.191337, 0.0913458}, 2}, {6.3509e-42,  4.77577e-18, 1., 1.11692e-7,  1.32739e-21}}, {{{0.471725, 0.608251, 0.721824, 0.706108,  0.900067}, {{1, 2}, {3, 1}, {0, 2}, {1, 0}, {3, 0}, {0, 2}},  0.781232, {0.836747, 0.139744, 0.11933, 0.51343}, {0.0677557,  0.131994, 0.0858186, 0.0569499, 0.192386, 0.176921, 0.118586,  0.0286681, 0.124806, 0.0195061, 0.00434935, 0.0373308, 0.0334607,  0.0817981, 0.110004, 0.115681}, -1}, {7.6335e-9, 0.880994,  0.119006, 1.82135e-12,  6.56903e-33}}, {{{0.702883, 0.649954, 0.797172, 0.608732,  0.563139}, {{0, 4}, {1, 3}, {1, 0}, {2, 4}, {1, 2}, {1, 2}},  0.530625, {0.283742, 0.269954, 0.903171, 0.101532}, {0.199798,  0.0616047, 0.00371317, 0.10172, 0.17113, 0.136798, 0.184207,  0.0973708, 0.133799, 0.103338, 0.102409, 0.187367, 0.0181188,  0.0142418, 0.161832, 0.0573756}, -1}, {1.4698e-26,  1.10674e-11, 0.00837016, 0.991559, 0.0000709945}}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      float pz[5];

      for (unsigned int j = 0; j < 5; ++j) { pz[j] = drand48 (); }

      estep (data[i].inputs.logalpha,
             5,
             data[i].inputs.tau,
             data[i].inputs.loglambda,
             pz,
             data[i].inputs.priorz,
             data[i].inputs.clamp,
             data[i].inputs.ratings,
             6);

      for (unsigned int j = 0; j < 5; ++j)
        {
          assert (fabs (pz[j] - data[i].pz[j]) <=
                  5e-4 * (1 + fabs (pz[j]) + fabs (data[i].pz[j])) ||
                  (fprintf (stderr, "%u: %g ?= %g\n", j, pz[j], data[i].pz[j]), 0));
        }
    }
}

int 
main (void)
{
  srand48 (69);

  test_estep ();

  return 0;
}
